/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab-modules.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include "CameraNavigator.h"

//===========================================================================================
const dylab::String dylab::CameraNavigator::COMPONENT_NAME = "cameraNavigator";

//===========================================================================================
dylab::CameraNavigator::CameraNavigator()
: ComEventListener(COMPONENT_NAME), mSimulation(NULL)
, mMove(Vector3::ZERO), mRotFlag(false), mRotX(0), mRotY(0), mSlowly(false)
, mMoveSpeed(128), mSlowMoveSpeed(32), mRotSpeedX(128), mRotSpeedY(128)
{
}
//-----------------------------------------------------------------------------
dylab::CameraNavigator::~CameraNavigator()
{
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::initialize(Simulation * _simulation)
{ DYLAB_TRACE_CALLS
    // store the simulation pointer
    mSimulation = _simulation; 

    // register our listener
    registerAsInputEventListener();
    registerAsGfxEventListener();    
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::loadFromPropertyTree(const PropertyTree & _pt)
{ DYLAB_TRACE_CALLS
	mMoveSpeed = _pt.getNodeValueT("speed", mMoveSpeed);
	mRotSpeedX = _pt.getNodeValueT("rotSpeedX", mRotSpeedX);
	mRotSpeedY = _pt.getNodeValueT("rotSpeedY", mRotSpeedY);
	mSlowMoveSpeed = _pt.getNodeValueT("slowSpeed", mSlowMoveSpeed);

	const PropertyTree::Node * ptNode;

	if ((ptNode = _pt.findNode("switchSlow")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onSwitchSlowMove);    
	if ((ptNode = _pt.findNode("moveForward")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveForward);    
	if ((ptNode = _pt.findNode("moveBackward")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveBackward);    
	if ((ptNode = _pt.findNode("moveLeft")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveLeft);    
	if ((ptNode = _pt.findNode("moveRight")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveRight);    
	if ((ptNode = _pt.findNode("moveUp")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveUp);    
	if ((ptNode = _pt.findNode("moveDown")) != NULL)
        mActions.bindAction(InputEvent::str2KeyCode(ptNode->getValue()), &CameraNavigator::onMoveDown);    
}
//-----------------------------------------------------------------------------
dylab::Simulation * dylab::CameraNavigator::getParentSimulation()
{
    return mSimulation;
}
//-----------------------------------------------------------------------------
const dylab::Simulation * dylab::CameraNavigator::getParentSimulation() const
{
    return mSimulation;
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::processEvent(const InputEvent & _inputEvent)
{               
    switch (_inputEvent.getType())
    {
    case InputEvent::KEY_DOWN:                        
    case InputEvent::KEY_UP:
        mActions.trySignal(_inputEvent.getKeyCode(), this, _inputEvent.getType());
        break;

    case InputEvent::MOUSE_DOWN:
        mRotFlag = true;
        break;

    case InputEvent::MOUSE_UP:
        mRotFlag = false;
        break;

    case InputEvent::MOUSE_MOVE:
        if (mRotFlag)
        {
            mRotX = - _inputEvent.getMouseRelX() * mRotSpeedX;
            mRotY = - _inputEvent.getMouseRelY() * mRotSpeedY;
        }
        break;
    }                    
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::processEvent(const GfxEvent & _gfxEvent)
{
    ComGfx::ICamera::ScopedExLock camera(mSimulation->getGfx());
    camera->move(mMove * (mSlowly ? mSlowMoveSpeed : mMoveSpeed) * static_cast<real_t>(_gfxEvent.getFrameDurationMS()) / DYLAB_R(1000));
    camera->rotate(mRotX, mRotY, 0);

    mRotX = 0;
    mRotY = 0;
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveForward(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(0, 0, -1);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(0, 0, -1);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveBackward(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(0, 0, 1);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(0, 0, 1);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveLeft(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(-1, 0, 0);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(-1, 0, 0);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveRight(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(1, 0, 0);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(1, 0, 0);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveUp(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(0, 1, 0);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(0, 1, 0);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onMoveDown(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mMove += Vector3(0, -1, 0);
        break;
    case InputEvent::KEY_UP:
        mMove -= Vector3(0, -1, 0);
        break;
    }
}
//-----------------------------------------------------------------------------
void dylab::CameraNavigator::onSwitchSlowMove(InputEvent::type_t _type)
{
    switch (_type)
    {
    case InputEvent::KEY_DOWN:
        mSlowly = true;
        break;
    case InputEvent::KEY_UP:
        mSlowly = false;
        break;
    }
}
//-----------------------------------------------------------------------------